/****************************** Module Header ******************************\
 * Module Name:  mxCollections.cs
 * Module Version:  1.0.0 (2011-9-28)
 * Copyright (c) AnyEB.Com (14507247@qq.com)
 * 
 * This class is used to extension collection instance's method.  It supplies 
 * useful extension methods, such as ToString(), FetchString() and so on.
 * 
 * This source is subject to the GPL License.
 * See http://www.gnu.org/licenses/gpl.html.
 * All other rights reserved.
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Data;
using System.Data.Common;
using System.Text;
using System.Xml;

namespace UCL
{
    /// <summary>
    /// 集合对象扩展类
    /// <para>提供Dictionary、IList、IDataReader等集合对象的扩展方法</para>
    /// </summary>
    public static class mxCollections
    {

        #region Dictionary对象的扩展方法

        /// <summary>
        /// 扩展Dictionary对象的ToString()方法
        /// </summary>
        /// <param name="odict"></param>
        /// <param name="format1"></param>
        /// <param name="format2"></param>
        /// <returns></returns>
        public static string ToStringKeyValue<K, V>(this Dictionary<K, V> odict, string format1 = "=", string format2 = "&")
        {
            StringBuilder sb = new StringBuilder();
            foreach (K key in odict.Keys)
            {
                sb.AppendFormat("{0}{1}{2}{3}", key, format1, odict[key], format2);
            }
            return sb.Length > 0 ? sb.Remove(sb.Length - format2.Length, format2.Length).ToString() : "";
        }

        /// <summary>
        /// 字典对象格式化XML输出
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="rootname"></param>
        /// <returns></returns>
        public static string ToXMLText<K, V>(this Dictionary<K, V> dict, string rootname = "root")
        {
            StringBuilder sb = new StringBuilder();
            if (rootname.Length > 0) sb.AppendFormat("<{0}>", rootname);
            foreach (K k in dict.Keys)
            {
                sb.AppendFormat("<{0}>{1}</{0}>", k, dict[k]);
            }
            if (rootname.Length > 0) sb.AppendFormat("</{0}>", rootname);
            return sb.ToString();
        }

        /// <summary>
        /// 字典对象转换成XML元素节点
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static XmlElement ToXMLElement<K, V>(this Dictionary<K, V> dict, string rootname = "root")
        {
            XmlElement xe = new XmlDocument().CreateElement(rootname);
            if (dict.Count == 0) return xe;
            xe.InnerXml = dict.ToXMLText("");
            return xe;
        }

        /// <summary>
        /// 反转字典键值
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static Dictionary<V, K> Reverse<K, V>(this Dictionary<K, V> dict)
        {
            Dictionary<V, K> outDict = new Dictionary<V, K>();
            foreach (K k in dict.Keys)
            {
                if (!outDict.ContainsKey(dict[k])) outDict.Add(dict[k], k);
            }
            return outDict;
        }

        /// <summary>
        /// 获取Dictionary对象中指定键的值，如果键不存在则返回空字符串
        /// </summary>
        /// <param name="oDict"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetValue(this Dictionary<string, string> oDict, string key)
        {
            return oDict.ContainsKey(key) ? oDict[key] : "";
        }

        /// <summary>
        /// 获取Dictionary对象中指定键的值，如果键不存在则返回空字符串
        /// </summary>
        /// <param name="oDict"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetValue(this Dictionary<string, string> oDict, int index)
        {
            int i = 0;
            foreach (string k in oDict.Keys)
            {
                if (i == index) return oDict[k];
                i++;
            }
            return "";
        }

        /// <summary>
        /// 追加元素，并返回追加后的集合，用于链式添加内容
        /// </summary>
        /// <param name="oDict"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Dictionary<K, V> AppendR<K, V>(this Dictionary<K, V> oDict, K key, V value)
        {
            oDict[key] = value;
            return oDict;
        }

        public static V[] ToArray<K, V>(this Dictionary<K, V>.ValueCollection vc)
        {
            V[] arr = new V[vc.Count];
            int i = 0;
            foreach (V v in vc)
            {
                arr[i] = v;
                i++;
            }
            return arr;
        }

        public static K[] ToArray<K, V>(this Dictionary<K, V>.KeyCollection kc)
        {
            K[] arr = new K[kc.Count];
            int i = 0;
            foreach (K v in kc)
            {
                arr[i] = v;
                i++;
            }
            return arr;
        }

        /// <summary>
        /// 获取所有键
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public static IList<string> GetKeys<T>(this Dictionary<string, T> o)
        {
            IList<string> list = new List<string>();
            foreach (string s in o.Keys)
            {
                list.Add(s);
            }
            return list;
        }

        /// <summary>
        /// 获取所有值
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="o"></param>
        /// <returns></returns>
        public static IList<V> GetValues<V>(this Dictionary<string, V> o)
        {
            IList<V> list = new List<V>();
            foreach (string s in o.Keys)
            {
                list.Add(o[s]);
            }
            return list;
        }

        /// <summary>
        /// 格式化字典输出
        /// <para>例如：this.lstParams.StringFormat&lt;object&gt;("{0}={1}")</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <param name="format">包含两个占位符的格式，占位符{0}=key,{1}=value</param>
        /// <returns></returns>
        public static string StringFormat<T>(this Dictionary<string, T> o, string format)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string s in o.Keys)
            {
                sb.AppendFormat(format, s, o[s]);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 修改字典中某个元素的值
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="o"></param>
        /// <param name="k"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Dictionary<K, V> Modify<K, V>(this Dictionary<K, V> o, K k, V v)
        {

            if (o.ContainsKey(k))
            {
                o[k] = v;
            }
            else
            {
                o.Add(k, v);
            }
            return o;
        }

        /// <summary>
        /// 添加键
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="o"></param>
        /// <param name="keys"></param>
        /// <returns></returns>
        public static Dictionary<K, V> AddKeys<K, V>(this Dictionary<K, V> o, params K[] keys)
        {
            foreach (K k in keys)
            {
                if (!o.ContainsKey(k)) o.Add(k, default(V));
            }
            return o;
        }

        /// <summary>
        /// 添加值
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="o"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static Dictionary<K, V> AddValues<K, V>(this Dictionary<K, V> o, params V[] values)
        {
            IList<K> keys = new List<K>(o.Keys);
            int i = 0;
            foreach (V v in values)
            {
                if (o.ContainsKey(keys[i])) o[keys[i]] = v;
                i++;
            }
            return o;
        }

        /// <summary>
        /// 字典转换成数据表
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="o"></param>
        /// <param name="tablename"></param>
        /// <returns></returns>
        public static DataTable ToIDNameDataTable<K, V>(this Dictionary<K, V> o, string tablename)
        {
            DataTable dt = new DataTable(tablename);
            dt.Columns.Add("ID", typeof(K));
            dt.Columns.Add("Name", typeof(V));
            foreach (K k in o.Keys)
            {
                dt.Rows.Add(k, o[k]);
            }
            return dt;
        }

        /// <summary>
        /// 将名值集合转换成键值集合
        /// </summary>
        /// <param name="nvc"></param>
        /// <returns></returns>
        public static Dictionary<string, object> ToDictionary(this NameValueCollection nvc)
        {
            Dictionary<string, object> dict = new Dictionary<string, object>();
            foreach (string n in nvc.Keys)
            {
                dict.Add(n, nvc[n]);
            }
            return dict;
        }
        #endregion

        #region IEnumerable对象的扩展方法

        /// <summary>
        /// 扩展数组的IndexOf方法
        /// <para>2013-8-16 by sutroon</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr"></param>
        /// <param name="compareFunc"></param>
        /// <returns></returns>
        public static int IndexOf<T>(this IEnumerable<T> arr, Func<T, bool> compareFunc)
        {
            if (arr == null) return -1;
            int i = 0;
            foreach (T item in arr)
            {
                if (compareFunc(item)) return i;
                i++;
            }
            return -1;
        }
        #endregion

        #region IList对象的扩展方法
        /// <summary>
        /// IList或值类型数组对象转为字符串值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="splitor"></param>
        /// <returns></returns>
        public static string ToString<T>(this IEnumerable<T> list, string splitor, string format = "{0}")
        {
            StringBuilder sb = new StringBuilder();
            foreach (T i in list)
            {
                sb.AppendFormat(format, i.ToString());
                sb.Append(splitor);
            }
            if (sb.Length > 0 && splitor.Length > 0) sb.Remove(sb.Length - splitor.Length, splitor.Length);
            return sb.ToString();
        }

        /// <summary>
        /// IEnumerator集合转换为字符串 2013-6-8 by sutroon
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="splitor"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static string ToString<T>(this IEnumerator<T> list, string splitor, string format = "{0}")
        {
            StringBuilder sb = new StringBuilder();
            while (list.MoveNext())
            {
                sb.AppendFormat(format, list.Current);
                sb.Append(splitor);
            }
            if (sb.Length > 0 && splitor.Length > 0) sb.Remove(sb.Length - splitor.Length, splitor.Length);
            return sb.ToString();
        }


        /// <summary>
        /// 截取并合并数组为字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr"></param>
        /// <param name="first"></param>
        /// <param name="splitor"></param>
        /// <returns></returns>
        public static string JoinToString<T>(this T[] arr, int first, string splitor)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = first; i < arr.Length; i++)
            {
                sb.AppendFormat("{0}{1}", arr[i], splitor);
            }
            if (sb.Length > splitor.Length) sb = sb.Remove(sb.Length - splitor.Length, splitor.Length);
            return sb.ToString();
        }

        /// <summary>
        /// 批量移除列表元素
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="list"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static IList<V> RemoveRangeR<V>(this IList<V> list, params V[] args)
        {
            foreach (V v in args) { list.Remove(v); }
            return list;
        }

        /// <summary>
        /// 安全地获取数组中的值
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="list"></param>
        /// <param name="index"></param>
        /// <param name="defv"></param>
        /// <returns></returns>
        /// <remarks>2014-5-30 by sutroon</remarks>
        public static V Get<V>(this IList<V> list, int index, V defv = default(V))
        {
            if (list == null || list.Count == 0 || list.Count <= index) return defv;
            return list[index];
        }

        public static IList<string> Wrap(this IList<string> list, string format)
        {
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = string.Format(format, list[i]);
            }
            return list;
        }
        /// <summary>
        /// 安全地获取数组中的时间值,如果不存在则返回1900年1月1日
        /// </summary>
        /// <param name="list"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static DateTime GetDateTime<V>(this IList<V> list, int index)
        {
            object val = list.Get(index);
            if (val == null) return DateTime.MinValue;
            DateTime datOut;
            return (DateTime.TryParse(val.ToString(), out datOut)) ? datOut : DateTime.MinValue;
        }

        /// <summary>
        /// 插入并返回新列表
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="list"></param>
        /// <param name="o"></param>
        /// <param name="isAtEnd"></param>
        /// <returns></returns>
        public static IList<V> InsertR<V>(this IList<V> list, V o, bool isAtEnd = false)
        {
            if (isAtEnd) { list.Add(o); } else { list.Insert(0, o); }
            return list;
        }

        /// <summary>
        /// 添加内容并返回新集合
        /// </summary>
        /// <param name="list"></param>
        /// <param name="lists"></param>
        public static IList<V> AppendR<V>(this IList<V> list, params IList<V>[] lists)
        {
            if (list.Count == 0) return list;
            foreach (IList<V> lst in lists)
            {
                foreach (V i in lst) { list.Add(i); }
            }
            return list;
        }

        /// <summary>
        /// 获取列表中随机N个元素
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="list"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static IList<V> SelectRandomTopN<V>(this IList<V> list, int count)
        {
            V[] arr = new V[count];
            Random rnd = new Random();
            while (count > 0)
            {
                if (!arr.Contains(list[rnd.Next(0, list.Count)]))
                {
                    arr[count] = list[rnd.Next(0, list.Count)];
                    count--;
                }
            }
            return arr;
        }

        /// <summary>
        /// 批量添加元素并返回新列表
        /// </summary>
        /// <typeparam name="V"></typeparam>
        /// <param name="list"></param>
        /// <param name="args"></param>
        public static IList<V> AddRangeR<V>(this IList<V> list, params V[] args)
        {
            foreach (V i in args) { list.Add(i); }
            return list;
        }

        /// <summary>
        /// 转换列表类型
        /// <para>如：Convert&lt;string, int&gt;((lst, s) =&gt; { int n; if (int.TryParse(s, out n)) { lst.Add(n); } })</para>
        /// </summary>
        /// <typeparam name="TInput">原类型</typeparam>
        /// <typeparam name="TOutput">新类型</typeparam>
        /// <param name="list"></param>
        /// <param name="act"></param>
        /// <returns></returns>
        /// <remarks>2015-1-29 by sutroon</remarks>
        public static IList<TOutput> Convert<TInput, TOutput>(this IEnumerable<TInput> list, Action<IList<TOutput>, TInput> act)
        {
            IList<TOutput> result = new List<TOutput>();
            foreach (TInput ele in list)
            {
                act(result, ele);
            }
            return result;
        }

        /// <summary>
        /// 获取字符串列表的总长度
        /// <para>如：</para>
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        /// <remarks>2015-2-5 by sutroon</remarks>
        public static long GetLength(this IEnumerable<string> list)
        {
            long l = 0;
            foreach (string s in list)
            {
                l += s.Length;
            }
            return l;
        }
        #endregion

    }
}
